package com.superme.filemanager.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.superme.common.beans.PageRequest;
import com.superme.common.beans.PageResponse;
import com.superme.common.constant.FileTypeConstant;
import com.superme.common.enums.ExceptionCodeEnum;
import com.superme.common.exceptions.BusinessException;
import com.superme.common.exceptions.FileException;
import com.superme.common.util.IdUtil;
import com.superme.filemanager.config.MinioConfig;
import com.superme.filemanager.config.RequestUserInfo;
import com.superme.filemanager.mapper.DeleteFileMapper;
import com.superme.filemanager.mapper.FileMapper;
import com.superme.filemanager.mapper.PhotoUrlMapper;
import com.superme.filemanager.pojo.entity.DeleteFile;
import com.superme.filemanager.pojo.entity.FileInfo;
import com.superme.filemanager.pojo.entity.PhotoUrl;
import com.superme.filemanager.service.FilesService;
import com.superme.filemanager.utils.MinioUtils;
import com.superme.filemanager.utils.MqUtils;
import io.minio.ObjectWriteResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.concurrent.ExecutorService;


/**
 * FileServiceImpl
 * 作者: yanruizhi
 * 时间: 2023/8/7 10:24
 */
@Service
@Slf4j
public class FileServiceImpl implements FilesService {

    @Resource
    private RequestUserInfo userInfo;
    @Resource
    private FileMapper fileMapper;
    @Resource
    private DeleteFileMapper deleteFileMapper;
    @Resource
    private MinioUtils minioUtils;
    @Resource
    private MinioConfig minioConfig;
    @Resource
    private ExecutorService executorService;
    @Resource
    private MqUtils mqUtils;
    @Resource
    private PhotoUrlMapper photoUrlMapper;

    @Override
    public PageResponse<FileInfo> getPage(FileInfo fileInfo, PageRequest page) {
        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(FileInfo::getCreateTime);
        Page<FileInfo> pageResult = fileMapper.selectPage(new Page<>(page.getCurrentPage(), page.getPageSize()),wrapper);
        return new PageResponse<>(pageResult);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFile(String fileInfoId) {
        if (StringUtils.isEmpty(fileInfoId)) {
            throw new BusinessException("文件id不能为空");
        }
        FileInfo fileInfo = fileMapper.selectById(fileInfoId);
        if (!ObjectUtils.isEmpty(fileInfo)) {
            LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(FileInfo::getId, fileInfoId);
            fileInfo.setIsDelete(1);
            fileMapper.update(fileInfo, queryWrapper);
        } else {
            throw new BusinessException(ExceptionCodeEnum.FILE_INFO_NOT_FOUND);
        }
        //删除文件记录
        DeleteFile deleteFile = new DeleteFile();
        deleteFile.setId(IdUtil.getId());
        deleteFile.setFileInfoId(fileInfoId);
        deleteFile.setCreateTime(LocalDateTime.now());
        deleteFileMapper.insert(deleteFile);
        //添加到消息队列，15天后删除文件
        mqUtils.deleteFile(deleteFile);
    }

    @Override
    public String getFileUrl(String objectName) {
        if (StringUtils.isEmpty(objectName)) {
            throw new BusinessException("对象名称不能为空");
        }
        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileInfo::getObjectName, objectName);
        Integer count = fileMapper.selectCount(queryWrapper);
        if (count == 0) {
            log.info("文件:{}不存在", objectName);
            throw new FileException(ExceptionCodeEnum.FILE_INFO_NOT_FOUND.getCode(), ExceptionCodeEnum.FILE_INFO_NOT_FOUND.getMessage());
        }
        boolean objectExist = minioUtils.isObjectExist(minioConfig.getBucketName(), objectName);
        if (!objectExist) {
            log.info("文件对象:{}不存在", objectName);
            throw new FileException(ExceptionCodeEnum.FILE_OBJECT_NOT_FOUND.getCode(), ExceptionCodeEnum.FILE_OBJECT_NOT_FOUND.getMessage());
        }
        String url = minioUtils.getPresignedObjectUrl(minioConfig.getBucketName(), objectName);
        return url.replace(minioConfig.getEndpoint(), minioConfig.getExternalLinkPrefix());
    }

    @Override
    @Transactional
    public void upload(MultipartFile file) {
        if (file.isEmpty()) {
            throw new RuntimeException("上传文件为空");
        }
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName(file.getOriginalFilename());
        fileInfo.setSize(file.getSize());
        String suffix = StringUtils.getFilenameExtension(file.getOriginalFilename());
        if (!Objects.requireNonNull(file.getOriginalFilename()).isEmpty()) {
            fileInfo.setSuffix(suffix);
        }
        fileInfo.setId(IdUtil.getId());
        String objectName = userInfo.getUserName() + "/" + IdUtil.getId();
        fileInfo.setObjectName(objectName);
        fileInfo.setCreateUser(userInfo.getUserName());
        fileInfo.setCreateUserId(userInfo.getUserId());
        fileInfo.setCreateTime(LocalDateTime.now());
        fileMapper.insert(fileInfo);

        boolean exists = minioUtils.bucketExists(minioConfig.getBucketName());
        if (!exists) {
            log.warn("bucket:{} 不存在", minioConfig.getBucketName());
            throw new BusinessException(ExceptionCodeEnum.BUCKET_NOT_FOUND.getCode(), ExceptionCodeEnum.BUCKET_NOT_FOUND.getMessage());
        }
        //判断文件夹是否存在
        boolean folderExist = minioUtils.isFolderExist(minioConfig.getBucketName(), userInfo.getUserName());
        if (!folderExist) {
            //不存在则根据用户名创建文件夹
            minioUtils.createDir(minioConfig.getBucketName(), userInfo.getUserName());
        }
        String userId = userInfo.getUserId();
        String userName = userInfo.getUserName();
        //异步步上传文件
        executorService.execute(() -> {
            try {
                ObjectWriteResponse response = minioUtils.uploadFile(file, objectName);//上传文件
                if (response.object() != null) {
                    // 创建图片访问地址
                    if (!StringUtils.isEmpty(suffix)) {
                        if (FileTypeConstant.PICTURE_TYPE_LIST.contains(suffix)) {
                            PhotoUrl photoUrl = new PhotoUrl();
                            photoUrl.setId(IdUtil.getId());
                            photoUrl.setFileSuffix(suffix);
                            photoUrl.setUrl(minioUtils.getPresignedObjectUrl(minioConfig.getBucketName(), objectName));
                            photoUrl.setName(fileInfo.getFileName());
                            photoUrl.setDescription("");
                            photoUrl.setCreateUserId(userId);
                            photoUrl.setCreateUserName(userName);
                            photoUrl.setCreateTime(LocalDateTime.now());
                            photoUrlMapper.insert(photoUrl);
                        }
                    }
                }
            } catch (Exception e) {
                log.error("上传文件失败,{}", e.getMessage());
                throw new FileException(ExceptionCodeEnum.FILE_EXCEPTION.getCode(), ExceptionCodeEnum.FILE_EXCEPTION.getMessage());
            }
        });
    }
}
